;; The first four lines of this file were added by Dracula.
;; They tell DrScheme that this is a Dracula Modular ACL2 program.
;; Leave these lines unchanged so that DrScheme can properly load this file.
#reader(planet "reader.rkt" ("cce" "dracula.plt") "modular" "lang")
(require "MImage.lisp")
(require "MCommon.lisp")
(require "MColorize.lisp")
(require "MRotate.lisp")
(require "MFlip.lisp")
(require "MGenerate.lisp")
(require "MOverlay.lisp")
(require "MResize.lisp")
(require "MThreshold.lisp")
(require "MCrop.lisp")
(require "MTrim.lisp")
(require "MDraw.lisp")
(require "MDecorate.lisp")


(module TImage
  (include-book "testing" :dir :teachpacks)
  (include-book "doublecheck" :dir :teachpacks)
  (include-book "avl-rational-keys" :dir :teachpacks)
  
  (import ICommon)
  (import IImage)
  (import IColorize)
  (import IRotate)
  (import IFlip)
  (import IGenerate)
  (import IOverlay)
  (import IResize)
  (import IThreshold)
  (import ICrop)
  (import ITrim)
  (import IDraw)
  (import IDecorate)

  
  ;;#####################################################
  ;;Helper Functions
  ;;#####################################################
  
  (defun GetTestImageBytes()
    '(66 77 70 0 0 0 0 0 0 0 54 0 0 0 40 0 0 0 2 0 0 0 2 0 0 0 1 0 24 0 0 0 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 76 177 34 232 162 0 0 0 0 0 0 36 28 237 0 0))
  
  (defun GetTestImageTree()
    (car (bmp->tree (GetTestImageBytes))))
  
  (defun GenerateFillerBytes (x)
    (if (> x 0)
        (append (list 0) (GenerateFillerBytes (- x 1)))
        nil))
  
  (defun AnyMatch(pixel colors)
    (if (consp colors)
        (if (equal pixel (car colors))
            t
            (AnyMatch pixel (cdr colors)))
        nil))
 
  (defun AssertAllPixelsHelper(tree width height x y colors)
    (let* ((nextX (getNextXCoordinate x width))
           (nextY (getNextYCoordinate x y width))
           (pixel (getPixel tree x y)))
      (if (isValidPixel nextX nextY width height)
          (if (AnyMatch pixel colors)
              (AssertAllPixelsHelper tree width height nextX nextY colors)
              nil)
          t)))
  
  (defun AssertAllPixels (tree r g b)
    (AssertAllPixelsHelper tree (getWidth tree) (getHeight tree) 1 (getHeight tree) (list (list r g b))))
  
  (defun AssertAllPixelsMulti (tree colors)
    (AssertAllPixelsHelper tree (getWidth tree) (getHeight tree) 1 (getHeight tree) colors))
  
  
  (defun AssertColumnHelper(tree width height x y r g b)
    (let* ((nextY (- y 1))
           (pixel (getPixel tree x y)))
      (if (isValidPixel x nextY width height)
          (if (equal pixel (list r g b))
              (AssertColumnHelper tree width height x nextY r g b)
              nil)
          t)))
  
  (defun AssertColumn(tree x r g b)
    (AssertColumnHelper tree (getWidth tree) (getHeight tree) x (getHeight tree) r g b))
  
  
  (defun AssertRowHelper(tree width height x y r g b)
    (let* ((nextX (+ x 1))
           (pixel (getPixel tree x y)))
      (if (isValidPixel nextX y width height)
          (if (equal pixel (list r g b))
              (AssertRowHelper tree width height nextX y r g b)
              nil)
          t)))
  
  (defun AssertRow(tree y r g b)
    (AssertRowHelper tree (getWidth tree) (getHeight tree) 1 y r g b))
  
  
  ;;#####################################################
  ;;Check Expects
  ;;#####################################################
  
  ;Common Module
  ;;#####################################################
  (check-expect (square 5) 25)
  (check-expect (square 0) 0)
  
  (check-expect (GetBMPSize 0 0) 54)
  (check-expect (GetBMPSize 8 8) 246)
  (check-expect (GetBMPSize 4 1) 66)
  
  (check-expect (hexCalculate (list 0)) 0)
  (check-expect (hexCalculate (list 10)) 10)
  (check-expect (hexCalculate (list 0 1)) 256)
  (check-expect (hexCalculate (list 50 1)) 306)
  (check-expect (hexCalculate (list 1 1 1)) 65793)
  
  (check-expect (int->bytes 0)     (list 0 0 0 0))
  (check-expect (int->bytes 10)    (list 10 0 0 0))
  (check-expect (int->bytes 256)   (list 0 1 0 0))
  (check-expect (int->bytes 306)   (list 50 1 0 0))
  (check-expect (int->bytes 65793) (list 1 1 1 0))
  
  (check-expect (remainingElements '(1) 1) nil)
  (check-expect (remainingElements '(1 2 3) 1) '(2 3))
  (check-expect (remainingElements '(1 2 3) 2) '(3))
  
  (check-expect (getElement '(1) 1) 1)
  (check-expect (getElement '(1 2) 1) 1)
  (check-expect (getElement '(1 2) 2) 2)
  
  (check-expect (getElements '(1) 1 1) '(1))
  (check-expect (getElements '(1 2) 1 1) '(1))
  (check-expect (getElements '(1 2) 1 2) '(1 2))

  (check-expect (validColor -1) nil)
  (check-expect (validColor 256) nil)
  (check-expect (validColor 0) t)
  (check-expect (validColor 255) t)
  (check-expect (validColor 127) t)

  (check-expect (validPixel (list 0 255 0)) t)
  (check-expect (validPixel (list 255 255 255)) t)
  (check-expect (validPixel (list 0 0 0)) t)
  (check-expect (validPixel (list 255 256 255)) nil)
  
  (check-expect (validPoint 0 0 10 10) nil)
  (check-expect (validPoint 1 0 10 10) nil)
  (check-expect (validPoint 1 1 10 10) t)
  (check-expect (validPoint 10 10 10 10) t)
  (check-expect (validPoint 11 10 10 10) nil)
  
  (check-expect (validPair 1 1 10 10 10 10) t)
  (check-expect (validPair 1 1 11 11 10 10) nil)
  (check-expect (validPair 10 10 1 1 10 10) nil)
  
  (check-expect (cap 0 0 255) 0)
  (check-expect (cap 255 0 255) 255)
  (check-expect (cap 127 0 255) 127)
  (check-expect (cap -1 0 255) 0)
  (check-expect (cap 256 0 255) 255)
  
  (check-expect (getLastElement  '(1)) 1)
  (check-expect (getLastElement  '(1 2)) 2)
  (check-expect (getLastElement  '(1 2 3)) 3)
  
  (check-expect (inRange 0 0 255) t)
  (check-expect (inRange 127 0 255) t)
  (check-expect (inRange 255 0 255) t)
  (check-expect (inRange -1 0 255) nil)
  (check-expect (inRange 256 0 255) nil)
  
  (check-expect (square 5) 25)
  (check-expect (inrange 10 5 15) 't)
  (check-expect (inrange 10 15 20) nil)
  (check-expect (hexCalculate (int->bytes 4376234)) 4376234)
  
  ;Image Module
  ;;#####################################################
  ;Test bmp->tree and tree->bmp
  (check-expect (car (bmp->tree (GetTestImageBytes))) (GetTestImageTree))
  (check-expect (GetTestImageBytes) (tree->bmp (GetTestImageTree)))
  (check-expect (tree->bmp (car (bmp->tree (GetTestImageBytes)))) (GetTestImageBytes))
  
  ;Test GetWidth and SetWidth
  (check-expect (GetWidth (GetTestImageTree)) 2)
  (check-expect (GetWidth (SetWidth (GetTestImageTree) 100)) 100)
  
  ;Test GetHeight and SetHeight
  (check-expect (GetHeight (GetTestImageTree)) 2)
  (check-expect (GetHeight (SetHeight (GetTestImageTree) 100)) 100)
  
  ;Test GetPixel, CreateRGB, and Insert Pixel
  (check-expect (CreateRGB 0 255 128) '(0 255 128))
  (check-expect (GetPixel (InsertPixel (GetTestImageTree) 1 1 0 0 0) 1 1 ) '(0 0 0))
  (check-expect (GetPixel (InsertPixel (GetTestImageTree) 1 2 255 255 255) 1 2 ) '(255 255 255))
  (check-expect (GetPixel (InsertPixel (GetTestImageTree) 2 2 26 54 128) 2 2 ) '(26 54 128))
  
  ;Test GetNextXCoordinate and GetNextYCoordinate
  (check-expect (GetNextXCoordinate 1 2) 2)
  (check-expect (GetNextXCoordinate 2 2) 1)
  (check-expect (GetNextYCoordinate 1 2 2) 2)
  (check-expect (GetNextYCoordinate 2 2 2) 1)
  
  ;Test IsValidPixel
  (check-expect (isValidPixel 1 1 2 2) t)
  (check-expect (isValidPixel 2 2 2 2) t)
  (check-expect (isValidPixel 0 1 2 2) nil)
  (check-expect (isValidPixel 1 3 2 2) nil)
  
  ;Resize Module
  ;;#####################################################
  (defconst *resizeheader* (list 1 2 3 4 5 6))
  (defconst *resizetree1*   (avl-insert (avl-insert (avl-insert (empty-tree) -1 *resizeheader*) -2  2) -3 2))
  (defconst *newTree* (avl-insert (avl-insert (avl-insert (empty-tree) -1 *resizeheader*) -2 4) -3 4))
  (defconst *resizetree2* (insertPixel *resizetree1* 1 2 100 100 100))
  (defconst *resizetree3* (insertPixel *resizetree2* 2 2 105 105 105))
  (defconst *resizetree4* (insertPixel *resizetree3* 1 1 110 110 110))
  (defconst *resizetree5* (insertPixel *resizetree4* 2 1 115 115 115))
  (defconst *matchingRowPixels* (list (list (list 3 6 (list 133 213 223))
                                            (list 7 6 (list 136 231 249))
                                            (list 11 6 (list 239 139 123))
                                            (list 15 6 (list 211 122 133)))
                                      (list (list 3 4 (list 231 123 222))
                                            (list 7 4 (list 245 234 124))
                                            (list 11 4 (list 255 255 255))
                                            (list 15 4 (list 122 131 145)))
                                      (list (list 3 2 (list 100 100 100))
                                            (list 7 2 (list 105 105 105))
                                            (list 11 2 (list 110 110 110))
                                            (list 15 2 (list 115 115 115)))))
  (defconst *tree1Shrk* (avl-insert (avl-insert (avl-insert (empty-tree) -1 *resizeheader*) -2  4) -3 4))
  (defconst *tree2Shrk* (insertPixel (insertPixel (insertPixel (insertPixel *tree1Shrk* 4 4 103 103 103) 3 4 102 102 102) 2 4 101 101 101) 1 4 100 100 100))
  (defconst *tree3Shrk* (insertPixel (insertPixel (insertPixel (insertPixel *tree2Shrk* 4 3 105 105 105) 3 3 106 106 106) 2 3 107 107 107) 1 3 108 108 108))
  (defconst *tree4Shrk* (insertPixel (insertPixel (insertPixel (insertPixel *tree3Shrk* 4 2 109 109 109) 3 2 110 110 110) 2 2 111 111 111) 1 2 112 112 112))
  (defconst *tree5Shrk* (insertPixel (insertPixel (insertPixel (insertPixel *tree4Shrk* 4 1 113 113 113) 3 1 114 114 114) 2 1 115 115 115) 1 1 116 116 116))
  (defconst *newTreeShrk* (avl-insert (avl-insert (avl-insert (empty-tree) -1 *resizeheader*) -2 2) -3 2))
  
  
  
  
  
  (check-expect  (calcBilinear 200 230 130 108 5 10 8 4 5 8) 200)
  (check-expect  (tree? (calcAndInsertPix *resizetree1*
                                          (list 200 234 199)
                                          (list 230 177 182)
                                          (list 130 255 239)
                                          (list 108 245 230) 5 10 8 4 5 8)) t)
  (check-expect (validCord 4 3 1 2) t)
  (check-expect (calcNextY 3 t) 2)
  (check-expect (car (calcNextX 2 1 4)) 3)
  (check-expect (tree? (bilinearInterpolateSquare *resizetree1*
                                                  (list 231 123 222)
                                                  (list 245 234 124)
                                                  (list 255 255 255)
                                                  (list 122 131 145) 6 10 5 8 6 10)) t)
  (check-expect (car (car (car (getListOfMatchingRowPix (list (list 1 3 '(231 123 222))
                                                              (list 2 3 '(245 234 124))
                                                              (list 3 3 '(255 255 255))
                                                              (list 1 2 '(122 131 145))
                                                              (list 3 2 '(200 234 199))) 3 '() '())))) 1)
  (check-expect (tree? (cadr (insertOldElements *newTree* *resizetree5* '() 1 8 8 8 (list 2 0) (list 2 0)))) t)
  (check-expect (tree? (interPolateBottomRightCorner *newTree* (list 7 7 (list 230 213 133)) 5 5)) t)
  (check-expect (tree? (interPolateRightSection *newTree* (list (list 15 6 (list 133 213 223))
                                                                (list 15 4 (list 136 231 249))
                                                                (list 15 2 (list 239 139 123))) 2 2)) t)
  (check-expect (tree? (interPolateBottomSection *newTree* (list (list 3 6 (list 133 213 223))
                                                                 (list 7 6 (list 136 231 249))
                                                                 (list 11 6 (list 239 139 123))
                                                                 (list 15 6 (list 211 122 133))) 3 3 '() '())) t)
  (check-expect (tree? (interPolateRowMainSection *newTree* (list (list 3 6 (list 133 213 223))
                                                                  (list 7 6 (list 136 231 249))
                                                                  (list 11 6 (list 239 139 123))
                                                                  (list 15 6 (list 211 122 133))) 
                                                  (list (list 3 4 (list 231 123 222))
                                                        (list 7 4 (list 245 234 124))
                                                        (list 11 4 (list 255 255 255))
                                                        (list 15 4 (list 122 131 145))) 3 3 '() '())) t)
  (check-expect (tree? (interPolateMainSection *newTree* *matchingRowPixels* 3 3))  t)
  (check-expect (car (car (getFarRightColumn *matchingRowPixels* '()))) 15)
  (check-expect (listp (car (createNewTree *resizetree5* *newTree* 16 8 8 (list 2 0) (list 2 0)))) t)
  (check-expect (car (car (calcPercentIncrease 8 8 16 16))) 2)
  (check-expect (tree? (car (resizeProportional *resizetree5* 2 2 4 4))) t)
  (check-expect (car (getRGBAverage (list (list 2 5 3) (list 5 7 1) (list 5 2 9)) 3 0 0 0)) 4)
  (check-expect (length (getPixelVals (list (list  1 2) (list 2 2) (list 1 1)) *resizetree5* '())) 3)
  (check-expect (validCordShrink 2 2 2 3) nil)
  (check-expect (calcNextYShrink 4 t) 3)
  (check-expect (car (calcNextXShrink 2 1 4)) 3)
  (check-expect (length (getCoordinates '() 5 14 8 16 5 16)) 12)
  (check-expect (length (calcCoordinates 5 16 4 3 1 1 20 20)) 12)
  (check-expect (tree? (insertCalculatedElements *newTreeShrk* *tree5Shrk* 1 2 2 2 2 2 0 0)) t)
  (check-expect (car (getPixel (createNewTreeShrink *tree5Shrk* 2 2 2 2 0 0) 1 2)) 104)
  (check-expect (cadr (getPixel (car (shrinkResize *tree5Shrk* 4 4 2 2)) 1 2)) 104)
  (check-expect (tree? (car (checkShrinkOrExpand *tree5Shrk* 4 4 2 2))) t)
  (check-expect (tree? (car (MainResize *tree5Shrk* (list 2 2)))) t)
  
  
  ;Threshold Module
  ;;#####################################################
  (defconst *thresholdheader* (list 1 2 3 4 5 6))
  (defconst *width* 2)
  (defconst *height* 2)
  (defconst *thresholdtree1* (avl-insert (avl-insert (avl-insert (empty-tree) -1 *thresholdheader*) -2 *width*) -3 *height*))
  (defconst *thresholdtree2* (insertPixel *thresholdtree1* 1 2 100 100 100))
  (defconst *thresholdtree3* (insertPixel *thresholdtree2* 2 2 105 105 105))
  (defconst *thresholdtree4* (insertPixel *thresholdtree3* 1 1 110 110 110))
  (defconst *thresholdtree5* (insertPixel *thresholdtree4* 2 1 115 115 115))
  
  (check-expect (pixelLessThanThreshold '(20 22 23) '(21 23 24)) t)
  (check-expect (car (getPixel (processThreshold *thresholdtree5* (createRGB 108 108 108) 1 *height* *width* *height*) 2 2)) 255)
  (check-expect (car (getPixel (car (MainThreshold *thresholdtree5* (list 109 109 109))) 1 2)) 255)
  
  


  ;Flip Module
  ;;#####################################################
  (defun include_meta_data (tr)
    (avl-insert (avl-insert (avl-insert tr -1 ()) -2 ()) -3 ()))
  
  (check-expect (include_meta_data ()) (flip-v (include_meta_data ())))
  (check-expect (include_meta_data ()) (flip-h (include_meta_data ())))
  
  
  ;;#####################################################
  ;;Random Generators
  ;;#####################################################
  
  (defrandom random-BMPHeader (width height)
    (let* ((BMPSize (GetBMPSize width height)))
      (let* ((WidthBytes        (int->bytes width))
             (HeightBytes       (int->bytes height))
             (SizeBytes         (int->bytes BMPSize))
             (SizeNoHeaderBytes (int->bytes (- BMPSize 54))))
        (append (list 66) (list 77) SizeBytes (GenerateFillerBytes 12) WidthBytes HeightBytes (GenerateFillerBytes 2) (list 24) (GenerateFillerBytes 5) SizeNoHeaderBytes (GenerateFillerBytes 16)))))
  
  (defrandom random-Pixel (rCap gCap bCap)
    (list (random-between 0 bCap) (random-between 0 gCap) (random-between 0 rCap)))
  
  (defrandom random-Pixels (x rCap gCap bCap)
    (if (> x 0)
        (append (random-Pixel rCap gCap bCap) (random-Pixels(- x 1) rCap gCap bCap))
        nil))
  
  (defrandom random-BMPLine (width rCap gCap bCap)
    (append (random-Pixels width rCap gCap bCap) (GenerateFillerBytes (mod Width 4))))
  
  (defrandom random-BMPPixels (width height rCap gCap bCap)
    (if (> height 0)
        (append (random-BMPLine width rCap gCap bCap) (random-BMPPixels width (- height 1) rCap gCap bCap))
        nil))
  
  (defrandom random-BMP ()
    (let* ((width (random-between 1 32))
           (height (random-between 1 32)))
      (let* ((header (random-BMPHeader width height))
             (pixels (random-BMPPixels width height 255 255 255)))
        (append header pixels))))
  
  (defrandom randomCapped-BMP(maxR maxG maxB)
    (let* ((width (random-between 1 32))
           (height (random-between 1 32)))
      (let* ((header (random-BMPHeader width height))
             (pixels (random-BMPPixels width height maxR maxG maxB)))
        (append header pixels))))
  
  (defrandom randomS-BMP ( w h)
    (let* ((header (random-BMPHeader w h))
           (pixels (random-BMPPixels w h 255 255 255)))
      (append header pixels)))
  
  
  ;;#####################################################
  ;;Property Tests
  ;;#####################################################
  
  
  ;Image Module
  ;;#####################################################
    (defproperty BMPTreeRoundTrip
      (bmpBytes :value (random-BMP))
      (equal (tree->bmp (car (bmp->tree bmpBytes))) bmpBytes))
    
    (defproperty BMPTreeSetWidth
      (bmpBytes :value (random-BMP)
       newWidth :value (random-between 1 32))
      (let* ((oldTree  (car (bmp->tree bmpBytes)))
             (newTree  (SetWidth oldTree newWidth))
             (newBytes (tree->bmp newTree))
             (height   (GetHeight oldTree))
             (newSize  (GetBMPSize newWidth height)))
        (and (equal (int->bytes newSize) (getElements newBytes 3 6)) (equal (int->bytes newWidth) (getElements newBytes 19 22)))))
    
    (defproperty BMPTreeSetHeight
      (bmpBytes  :value (random-BMP)
       newHeight :value (random-between 1 32))
      (let* ((oldTree  (car (bmp->tree bmpBytes)))
             (newTree  (SetHeight oldTree newHeight))
             (newBytes (tree->bmp newTree))
             (width    (GetWidth oldTree))
             (newSize  (GetBMPSize width newHeight)))
        (and (equal (int->bytes newSize) (getElements newBytes 3 6)) (equal (int->bytes newHeight) (getElements newBytes 23 26)))))
    
    (defproperty InsertPixelTest
      (bmpBytes  :value (random-BMP)
       newHeight :value (random-between 1 32)
       newWidth  :value (random-between 1 32)
       pixel-x   :value (random-between 1 newWidth)
       pixel-y   :value (random-between 1 newHeight)
       red       :value (random-between 0 255)
       green     :value (random-between 0 255)
       blue      :value (random-between 0 255))
      (let* ((oldTree    (car (bmp->tree bmpBytes)))
             (newDimTree (SetWidth (SetHeight oldTree newHeight) newWidth))
             (newPixTree (insertPixel newDimTree pixel-x pixel-y red green blue)))
        (equal (getPixel newPixTree pixel-x pixel-y) (createRGB red green blue))))
  
  ;Colorize Module
  ;;#####################################################
  
  (defproperty ColorizeRoundTripAddTest
    (deltaR   :value (random-between 0 255)
     deltaG   :value (random-between 0 255)
     deltaB   :value (random-between 0 255)
     bmpBytes :value (randomCapped-BMP (- 255 deltaR) (- 255 deltaG) (- 255 deltaB)))
    (let* ((oldTree    (car (bmp->tree bmpBytes)))
           (midTree    (car (MainColorize oldTree (list    deltaR     deltaG     deltaB  "ADD"))))
           (finalTree  (car (MainColorize midTree (list (- deltaR) (- deltaG) (- deltaB) "ADD"))))
           (finalBytes (tree->bmp finalTree)))
      (equal bmpBytes finalBytes)))
  
  (defproperty ColorizeRoundTripMulTest
    (rCap :value (random-between 0 127)
     gCap :value (random-between 0 127)
     bCap :value (random-between 0 127)
     bmpBytes :value (randomCapped-BMP rCap gCap bCap))
    (let* ((oldTree    (car (bmp->tree bmpBytes)))
           (midTree    (car (MainColorize oldTree (list  2  2  2 "MUL"))))
           (finalTree  (car (MainColorize midTree (list .5 .5 .5 "MUL"))))
           (finalBytes (tree->bmp finalTree)))
      (equal bmpBytes finalBytes)))

  ;;Rotate Module
  ;;#####################################################
    (defproperty RotateRoundTrip1
      (bmpBytes :value (random-BMP))
      (let* ((oldTree    (car (bmp->tree bmpBytes)))
             (midTree1   (car (MainRotate oldTree  (list 90))))
             (midTree2   (car (MainRotate midTree1 (list 90))))
             (midTree3   (car (MainRotate midTree2 (list 90))))
             (finalTree  (car (MainRotate midTree3 (list 90))))
             (finalBytes (tree->bmp finalTree)))
      (equal bmpBytes finalBytes)))
    
    (defproperty RotateRoundTrip2
      (bmpBytes :value (random-BMP))
      (let* ((oldTree    (car (bmp->tree bmpBytes)))
             (midTree    (car (MainRotate oldTree (list 180))))
             (finalTree  (car (MainRotate midTree (list 180))))
             (finalBytes (tree->bmp finalTree)))
      (equal bmpBytes finalBytes)))
    
    (defproperty RotateRoundTrip3
      (bmpBytes :value (random-BMP))
      (let* ((oldTree    (car (bmp->tree bmpBytes)))
             (midTree1   (car (MainRotate oldTree  (list 270))))
             (midTree2   (car (MainRotate midTree1 (list 270))))
             (midTree3   (car (MainRotate midTree2 (list 270))))
             (finalTree  (car (MainRotate midTree3 (list 270))))
             (finalBytes (tree->bmp finalTree)))
      (equal bmpBytes finalBytes)))
    
    (defproperty RotateFlipRoundTrip
      (bmpBytes :value (random-BMP))
      (let* ((oldTree    (car (bmp->tree bmpBytes)))
             (midTree1   (car (MainRotate oldTree  (list 180))))
             (midTree2   (car (MainFlip   midTree1 (list "v"))))
             (finalTree  (car (MainFlip   midTree2 (list "h"))))
             (finalBytes (tree->bmp finalTree)))
      (equal bmpBytes finalBytes)))
  
  ;;Generate Module
  ;;#####################################################
    
    (defproperty GenerateSolidTest
      (bmpBytes :value (random-BMP)
       red      :value (random-between 0 255)
       green    :value (random-between 0 255)
       blue     :value (random-between 0 255))
      (let* ((oldTree    (car (bmp->tree bmpBytes)))
             (finalTree  (car (MainGenerate oldTree (list "SOLID" red green blue)))))
        (AssertAllPixels  finalTree red green blue)))
    
    (defproperty GenerateLinearGradientHorizontalTest
      (width    :value (random-between 2 32)
       height   :value (random-between 2 32)
       red1     :value (random-between 0 255)
       green1   :value (random-between 0 255)
       blue1    :value (random-between 0 255)
       red2     :value (random-between 0 255)
       green2   :value (random-between 0 255)
       blue2    :value (random-between 0 255)
       bmpBytes :value (randomS-BMP width height))
      (let* ((oldTree    (car (bmp->tree bmpBytes)))
             (finalTree  (car (MainGenerate oldTree (list "LINEARGRADIENT" "HORIZONTAL" 1 (- width 1) red1 green1 blue1 red2 green2 blue2)))))
        (and (AssertColumn finalTree 1 red1 green1 blue1) (AssertColumn finalTree width red2 green2 blue2))))
  
    (defproperty GenerateLinearGradientVerticalTest
      (width    :value (random-between 2 32)
       height   :value (random-between 2 32)
       red1     :value (random-between 0 255)
       green1   :value (random-between 0 255)
       blue1    :value (random-between 0 255)
       red2     :value (random-between 0 255)
       green2   :value (random-between 0 255)
       blue2    :value (random-between 0 255)
       bmpBytes :value (randomS-BMP width height))
      (let* ((oldTree    (car (bmp->tree bmpBytes)))
             (finalTree  (car (MainGenerate oldTree (list "LINEARGRADIENT" "VERTICAL" 1 (- height 1) red1 green1 blue1 red2 green2 blue2)))))
        (and (AssertRow finalTree 1 red1 green1 blue1) (AssertRow finalTree height red2 green2 blue2))))
  
  (defproperty GenerateCircularGradientTest
    (width    :value (random-between 4 32)
     height   :value (random-between 4 32)
     radius   :value (- (random-between 2 (floor (min width height) 2)) 1)
     red1     :value (random-between 0 255)
     green1   :value (random-between 0 255)
     blue1    :value (random-between 0 255)
     red2     :value (random-between 0 255)
     green2   :value (random-between 0 255)
     blue2    :value (random-between 0 255)
     bmpBytes :value (randomS-BMP width height))
    (let* ((centerX    (floor width 2))
           (centerY    (floor height 2))
           (oldTree    (car (bmp->tree bmpBytes)))
           (finalTree  (car (MainGenerate oldTree (list "CIRCULARGRADIENT" centerX centerY radius red1 green1 blue1 red2 green2 blue2)))))
      (and (AssertRow finalTree 1 red2 green2 blue2) (AssertRow finalTree height red2 green2 blue2)
           (AssertColumn finalTree 1 red2 green2 blue2) (AssertColumn finalTree width red2 green2 blue2)
           (equal (getPixel finalTree centerX centerY) (createRGB red1 green1 blue1)))))
  
  (defproperty GenerateCheckerBoardTest
    (width    :value (random-between 4 32)
     height   :value (random-between 4 32)
     sWidth   :value (random-between 1 (- width 1))
     sHeight  :value (random-between 1 (- height 1))
     red1     :value (random-between 0 255)
     green1   :value (random-between 0 255)
     blue1    :value (random-between 0 255)
     red2     :value (random-between 0 255)
     green2   :value (random-between 0 255)
     blue2    :value (random-between 0 255)
     bmpBytes :value (randomS-BMP width height))
    (let* ((oldTree    (car (bmp->tree bmpBytes)))
           (finalTree  (car (MainGenerate oldTree (list "CHECKERBOARD" sWidth sHeight red1 green1 blue1 red2 green2 blue2)))))
      (and (AssertAllPixelsMulti finalTree (list (list red1 green1 blue1) (list red2 green2 blue2))))))
  
  (defproperty GenerateInterlaceHorizontalTest
    (width    :value (random-between 4 32)
     height   :value (random-between 4 32)
     iHeight  :value (random-between 1 (- height 1))
     red1     :value (random-between 0 255)
     green1   :value (random-between 0 255)
     blue1    :value (random-between 0 255)
     red2     :value (random-between 0 255)
     green2   :value (random-between 0 255)
     blue2    :value (random-between 0 255)
     bmpBytes :value (randomS-BMP width height))
    (let* ((oldTree       (car (bmp->tree bmpBytes)))
           (interlaceTree (car (MainGenerate oldTree (list "INTERLACEHORIZONTAL"  iHeight red1 green1 blue1 red2 green2 blue2))))
           (checkerTree   (car (MainGenerate oldTree (list "CHECKERBOARD" width iHeight red1 green1 blue1 red2 green2 blue2)))))
      (equal interlaceTree checkerTree)))
  
    (defproperty GenerateInterlaceVerticalTest
    (width    :value (random-between 4 32)
     height   :value (random-between 4 32)
     iWidth   :value (random-between 1 (- height 1))
     red1     :value (random-between 0 255)
     green1   :value (random-between 0 255)
     blue1    :value (random-between 0 255)
     red2     :value (random-between 0 255)
     green2   :value (random-between 0 255)
     blue2    :value (random-between 0 255)
     bmpBytes :value (randomS-BMP width height))
    (let* ((oldTree       (car (bmp->tree bmpBytes)))
           (interlaceTree (car (MainGenerate oldTree (list "INTERLACEVERTICAL"  iWidth red1 green1 blue1 red2 green2 blue2))))
           (checkerTree   (car (MainGenerate oldTree (list "CHECKERBOARD" iWidth height red1 green1 blue1 red2 green2 blue2)))))
      (equal interlaceTree checkerTree)))
  


  ;Overlay Module
  ;;#####################################################
  (defproperty OverlayAddSubRoundTripTest
    (deltaR   :value (random-between 0 255)
     deltaG   :value (random-between 0 255)
     deltaB   :value (random-between 0 255)
     bmpBytes :value (randomCapped-BMP (- 255 deltaR) (- 255 deltaG) (- 255 deltaB)))
    (let* ((oldTree    (car (bmp->tree bmpBytes)))
           (midTree    (car (MainOverlay oldTree (list "SOLID" deltaR deltaG deltaB "ADD"))))
           (finalTree  (car (MainOverlay midTree (list "SOLID" deltaR deltaG deltaB "SUB"))))
           (finalBytes (tree->bmp finalTree)))
      (equal bmpBytes finalBytes)))

  
  
  (defproperty OverlayMulTest
    (red      :value (random-between 0 127)
     green    :value (random-between 0 127)
     blue     :value (random-between 0 127)
     bmpBytes :value (random-BMP))
    (let* ((oldTree    (car (MainGenerate (car (bmp->tree bmpBytes)) (list "SOLID" red green blue))))
           (midTree    (car (MainOverlay oldTree (list "SOLID" 2 2 2 "MUL"))))
           (finalTree  (car (MainOverlay midTree (list "SOLID" red green blue "SUB")))))
     (equal oldTree finalTree)))
  
  ;;Resize Module
  ;;#####################################################
  
  (defrandom incrimenting-alist ()
    (let* ((elem1 (random-between 0 255))
           (elem2 (random-between 0 255))
           (elem3 (random-between 0 255)))
      (list elem1 elem2 elem3)))
  
  (defrandom mixedList (rowNum)
    (let* ((elem1 (list (random-between 0 4) rowNum (list (random-between 0 255) (random-between 0 255) (random-between 0 255))))
           (elem2 (list (random-between 0 4) rowNum (list (random-between 0 255) (random-between 0 255) (random-between 0 255))))
           (elem3 (list (random-between 0 4) rowNum (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))))
      (append (list elem1) (list elem2) (list elem3))))
  
  (defrandom makeTree (treeWidth treeHeight)
    (let* ((returnTree (avl-insert (avl-insert (avl-insert (empty-tree) -1 *resizeheader*) -2 treeWidth) -3 treeHeight)))
      returnTree))
  
  (defrandom getRandomListOfPixels (sizeOfList returnList)
    (let* ((num1 (random-between 1 255))
           (num2 (random-between 1 255))
           (num3 (random-between 1 255))
           (pixelList (list num1 num2 num3)))
      (if (equal sizeOfList 1)
          (append returnList (list pixelList))
          (getRandomListOfPixels (- sizeOfList 1) (append returnList (list pixelList))))))
  
  (defproperty calcBilinear-returns-integer 
    (Q11Val :where (integerp Q11Val) :value (random-between 0 255)
            Q21Val :where (integerp Q21Val) :value (random-between 0 255)
            Q12Val :where (integerp Q12Val) :value (random-between 0 255)
            Q22Val :where (integerp Q22Val) :value (random-between 0 255))
    (equal (integerp (calcBilinear Q11Val Q21Val Q12Val Q22Val 1 4 4 1 1 4)) t))
  
  (defproperty calcAndInsertPix-returns-tree 
    (Q11 :where (listp Q11) :value (incrimenting-alist)
         Q21 :where (listp Q21) :value (incrimenting-alist)
         Q12 :where (listp Q12) :value (incrimenting-alist)
         Q22 :where (listp Q22) :value (incrimenting-alist))
    (equal (tree? (calcAndInsertPix *newTree* Q11 Q21 Q12 Q22 1 4 4 1 1 4)) t))
  
  (defproperty validCord-returns-boolean
    (nextX :where (integerp nextX) :value (random-between 0 4)
           nextY :where (integerp nextY) :value (random-between 0 4)
           beginWidth :where (booleanp beginWidth) :value (random-boolean)
           height :where (integerp height) :value (random-between 0 5))
    (equal (booleanp (validCord nextX nextY beginWidth height)) t))
  
  (defproperty calcNextY-returns-integer
    (y :where (integerp y) :value (random-integer)
       endOfX :where (booleanp endOfX) :value (random-boolean))
    (equal (integerp (calcNextY y endOfX)) t))
  
  (defproperty calcnextX-returns-integer
    (x :where (integerp x) :value (random-between 0 4))
    (equal (listp (calcNextX x 0 4)) t))
  
  
  (defproperty bilinearInterpolateSquare-returns-tree
    (Q11 :where (listp Q11) :value (incrimenting-alist)
         Q21 :where (listp Q21) :value (incrimenting-alist)
         Q12 :where (listp Q12) :value (incrimenting-alist)
         Q22 :where (listp Q22) :value (incrimenting-alist)
         x1  :where (integerp x1) :value (random-between 1 4)
         x2  :where (integerp x2) :value (random-between 6 10)
         y1  :where (integerp y1) :value (random-between 1 4)
         y2  :where (integerp y2) :value (random-between 6 10))
    (equal (tree? (bilinearInterpolateSquare *newTree* Q11 Q21 Q12 Q22 x1 x2 y1 y2 x1 y2)) t))

  
  (defproperty getListOfMatchingRowPix-second-rowis-two 
    (row1 :where (listp row1) :value (mixedList 1)
          row2 :where (listp row2) :value (mixedList 2)
          row3 :where (listp row3) :value (mixedList 3)
          finalList :where (listp finalList) :value (append row1 row2 row3))
    (equal (cadr (car (cadr (getListOfMatchingRowPix finalList 1 '() '())))) 2))
  
  
  (defproperty  interPolateBottomRightCorner-returns-tree
    (randPixel :where (listp randPixel) :value (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
    (equal (tree? (interPolateBottomRightCorner *newTree* (list 2 2 randPixel) 2 2)) t))
  
  (defproperty interPolateRightSection-returns-tree
    (elem1 :where (listp elem1) :value (list 4 4 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           elem2 :where (listp elem1) :value (list 4 2 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           finalList :where (listp finalList) :value (append  (list elem1) (list elem2)))
    (equal (tree? (interPolateRightSection *newTree* finalList 1 1)) t))
  
  
  (defproperty interPolateBottomSection-returns-tree
    (elem1 :where (listp elem1) :value (list 2 4 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           elem2 :where (listp elem1) :value (list 4 4 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           finalList :where (listp finalList) :value (append  (list elem1) (list elem2)))
    (equal (tree? (interPolateBottomSection *newTree* finalList 2 2 '() '())) t))
  
  
  
  (defproperty interPolateRowMainSection-returns-tree
    (elem1 :where (listp elem1) :value (list 2 4 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           elem2 :where (listp elem1) :value (list 4 4 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           elem3 :where (listp elem1) :value (list 2 2 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           elem4 :where (listp elem1) :value (list 4 2 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           mainRow :where (listp mainRow) :value (append  (list elem1) (list elem2))
           secondRow :where (listp secondRow) :value (append  (list elem3) (list elem4)))
    (equal (tree? (interPolateRowMainSection *newTree* mainRow secondRow 2 2 '() '())) t))
  
  
  (defproperty interPolateMainSection-returns-tree
    (elem1 :where (listp elem1) :value (list 2 4 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           elem2 :where (listp elem1) :value (list 4 4 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           elem3 :where (listp elem1) :value (list 2 2 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           elem4 :where (listp elem1) :value (list 4 2 (list (random-between 0 255) (random-between 0 255) (random-between 0 255)))
           mainRow :where (listp mainRow) :value (append  (list elem1) (list elem2))
           secondRow :where (listp secondRow) :value (append  (list elem3) (list elem4))
           finalList :where (listp finalList) :value (append  (list mainRow) (list secondRow)))
    (equal (tree? (interPolateMainSection *newTree* finallist 2 2)) t))
  
  (defproperty getFarRightColumn-has-size-equal-to-number-of-rows
    (row1 :where (listp row1) :value (mixedList 1)
          row2 :where (listp row2) :value (mixedList 2)
          row3 :where (listp row3) :value (mixedList 3)
          row4 :where (listp row4) :value (mixedList 4)
          finalList :where (listp finalList) :value (append row1 row2 row3 row4))
    (equal (len (getFarRightColumn finalList '())) (len finalList)))
 
  
  (defproperty  insertOldElements-inserts-in-right-location
      (inputTree :value *resizetree5*
                  xLoc :value (random-between 1 2)
                  yLoc :value (random-between 1 2)
                  newXLoc :value (* xLoc 2)
                  newYLoc :value (* yLoc 2))
      (equal (cdr (avl-retrieve (cdr (avl-retrieve (cadr (insertOldElements *newTree* *resizetree5* '() 1 2 2 2 (list 2 0) (list 2 0))) newYLoc)) newXLoc))
              (cdr (avl-retrieve (cdr (avl-retrieve inputTree yLoc)) xLoc))))
  
 
  (defproperty calcPercentIncrease-returns-div-current-width-and-newWidth
    (currentTreeWidth :value (random-between 4 32)
                      currentTreeHeight :value (random-between 4 32)
                      newWidth   :value (random-between 32 64)
                      newHeight  :value (random-between 32 64))
    (equal (car (car (calcPercentIncrease currentTreeWidth currentTreeHeight newWidth newHeight))) (/ newWidth currentTreeWidth)))
  

  (defproperty getRGBAverage-returns-integer-listp
    (repBoxSize :value (random-between 2 10)
                oldTreePixelVals :value (getRandomListOfPixels repBoxSize '()))
    (equal (integer-listp (getRGBAverage oldTreePixelVals repBoxSize 0 0 0)) t))
  
  (defproperty getPixelVals-returns-a-list-of-lists-of-length-equal-to-inputcords-length
    (coordinates :value (getCoordinates '() 1 1 2 2 1 2)
          randElement :value (random-Between 1 4))
    (equal (LEN (getPixelVals coordinates *resizetree5* '())) (LEN coordinates)))
  
  (defproperty validCordShirink-returns-true-when-nextY-is-Less-than-height
    (height :value (random-between 4 8)
            nextY :value (random-between 1 (- height 1)))
    (equal (validCordShrink 1 nextY 1 height) nil))
  
  (defproperty  calcNextYShrink-returns-integer
    (y :where (integerp y) :value (random-integer)
       endOfX :where (booleanp endOfX) :value (random-boolean))
    (equal (integerp (calcNextYShrink y endOfX)) t))
  
  (defproperty calcNextXShrink-returns-integer
    (x :where (integerp x) :value (random-between 0 4))
    (equal (listp (calcNextXShrink x 0 4)) t))
  
  ;Threshold Module
  ;;#####################################################
  (defproperty test-pixelLessThanThreshold :repeat 1000
    (a :value (random-integer)
       :where (< a 100)
       b :value (random-integer)
         :where (< b 100)
         c :value (random-integer)
           :where (< c 100))
    (let ((pixel (createRGB a b c))
          (threshOld (createRGB 100 100 100)))
      (equal (pixelLessThanThreshold pixel threshOld) t)))
  
    (defproperty test-processThreshold :repeat 1000
    (a :value (random-integer)
       :where (< a 205)
       b :value (random-integer)
         :where (< b 205)
         c :value (random-integer)
           :where (< c 205))
    (let ((pixel (createRGB a b c)))
      (equal (car (getPixel (processThreshold (insertPixel *thresholdtree4* 2 1 a b c) pixel 1 *height* *width* *height*) 2 1)) 255)))
  
    (defproperty test-MainThreshold :repeat 1000
    (a :value (random-integer)
       :where (< a 120)
       b :value (random-integer)
         :where (< b 120)
         c :value (random-integer)
           :where (< c 120))
    (let ((pixel (createRGB a b c)))
      (equal (car (getPixel (car (MainThreshold (insertPixel *thresholdtree4* 2 1 a b c) (list 120 120 120))) 2 1)) 255)))
  
  ;Flip Module
  ;#####################################################
  (defrandom bld_tr (tr w h w_org)
    (if (equal w 0)
        (if (equal h 0)              
            (insertPixel tr w h (random-between 0 255) (random-between 0 255) (random-between 0 255))
            (bld_tr (insertPixel tr w h (random-between 0 255) (random-between 0 255) (random-between 0 255)) w_org (1- h) w_org))
        (bld_tr (insertPixel tr w h (random-between 0 255) (random-between 0 255) (random-between 0 255)) (1- w) h w_org)))
  
  (defproperty p1 :repeat 100
    (width  :value (random-between 1 64)
            height :value (random-between 1 64)
            img    :value (bld_tr () width height width))
    (equal (flip-v (flip-v (include_meta_data img))) (include_meta_data img)))
  
  (defproperty p2 :repeat 100
    (width  :value (random-between 1 64)
            height :value (random-between 1 64)
            img    :value (bld_tr () width height width))
    (equal (flip-h (flip-h (include_meta_data img))) (include_meta_data img)))
  
  
  ;Common Module
  ;;#####################################################

  (defproperty hexcalc-intbytes-roundtrip
    (val    :value (random-between 0 16000000))
    (equal (hexcalculate (int->bytes val)) val))
  
  
  ;;Crop Module
  ;;#####################################################
  
  (defproperty crop-no-size-change
    (width   :value (random-between 10 30)
             height  :value (random-between 10 30)
             image   :value (randomS-BMP width height))
    (equal image (tree->bmp (car (MainCrop (car (bmp->tree image)) (list 1 1 width height))))))
  
  (defproperty crop-change-size
    (width   :value (random-between 20 30)
             height  :value (random-between 20 30)
             x1      :value (random-between 4 10)
             y1      :value (random-between 4 10)
             x2      :value (random-between 12 20)
             y2      :value (random-between 12 20)
             image   :value (randomS-BMP width height))
    (let* ((tree (car (MainCrop (car (bmp->tree image)) (list x1 y1 x2 y2))))
           (width (getWidth tree))
           (height (getHeight tree)))
      (and (equal width (+ (- x2 x1) 1)) (equal height (+ (- y2 y1) 1)))))
  
  ; Trim Module
  ;;#####################################################
  (defproperty trim-smaller
    (width   :value (random-between 10 30)
             height  :value (random-between 10 30)
             image   :value (randomS-BMP width height))
    (let* ((image2Tree (car (MainTrim (car (bmp->tree image)) nil))))
      (and (<= (getWidth image2Tree) width)
           (<= (getHeight image2Tree) height))))

; ; Not working due to a problem in decorate -- (Not sure about this... jrollman)
;  (defproperty trip-decorate-roundtrip
;    (width   :value (random-between 10 30)
;     height  :value (random-between 10 30)
;         r   :value (random-between 0 255)
;         g   :value (random-between 0 255)
;         b   :value (random-between 0 255)
;         w   :value (random-between 3 10)
;     image   :value (randomS-BMP width height))
;    (let* ((color (list r g b))
;           (decorated (car (MainDecorate (car (bmp->tree image)) (cons w color))))
;           (trimmed (car (MainTrim decorated nil))))
;      (or (equal color (getPixel (car (bmp->tree image)) 1 1)) (equal (tree->bmp trimmed) image))))
  
; Not working due to problem in decorate. -- (Not sure about this... jrollman)
;  (defproperty trip-decorate-roundtrip
;    (        r   :value (random-between 100 100)
;             g   :value (random-between 100 100)
;             b   :value (random-between 100 100)
;             w   :value (random-between 9 9)
;             image   :value (randomCapped-BMP 0 0 0))
;    (let* ((imageTree (car (bmp->tree image)))
;           (decorated (car (MainDecorate imageTree (list w r g b))))
;           (trimmed (car (MainTrim decorated nil))))
;      (princ$ (list w (getWidth imageTree)(getHeight imageTree) (getWidth decorated)(getHeight decorated) (getWidth trimmed)(getHeight trimmed) ))))
;      ;(equal (getWidth trimmed) (getWidth imageTree))))
  
  
  
  )
  (link RTImage
        (MCommon MImage MColorize MRotate MFlip MGenerate MOverlay MResize MThreshold MCrop MTrim MDecorate MDraw TImage))

(invoke RTImage)